#include "gd32f30x.h"
#include "stdint.h"
#include "DevicesCRC.h"
#include "DevicesRTC.h"



static void cRtcBkpInit(void);


void vRtcInit(void)
{
    uint32_t uiPrescaler = 0;

    /* enable PMU and BKPI clocks */
    rcu_periph_clock_enable(RCU_BKPI);
    rcu_periph_clock_enable(RCU_PMU);

    /* allow access to BKP domain */
    pmu_backup_write_enable();

CODE_BKP_INIT:
    /* 备份寄存器的值，如果是正常的0xA5A5，则表示系统关机后，RTC一直运行正常 */
    if (bkp_read_data(BKP_DATA_0) != 0xA5A5)
    {
        /* 恢复备份数据 */
        cRtcBkpInit();

        /* enable LXTAL */
        rcu_osci_on(RCU_LXTAL);
//        /* wait till LXTAL is ready */
//        if(rcu_osci_stab_wait(RCU_LXTAL) == SUCCESS)
//        {
//            /* select RCU_LXTAL as RTC clock source */
//            rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
//        }
//        else
        {
            /* select RCU_HXTAL_DIV_128 as RTC clock source */
            rcu_rtc_clock_config(RCU_RTCSRC_HXTAL_DIV_128);
        }

        /* enable RTC Clock */
        rcu_periph_clock_enable(RCU_RTC);

        /* wait for RTC registers synchronization */
        rtc_register_sync_wait();
        /* wait until last write operation on RTC registers has finished */
        rtc_lwoff_wait();

        vRtcTimestampSet(0);
    }

    /* 由不同的时钟源，设定不同的分频系数 */
    switch((RCU_BDCTL & RCU_BDCTL_RTCSRC) >> 8)
    {
        case 1: uiPrescaler = 32767; break;
        case 3: uiPrescaler = HXTAL_VALUE / 128; break;

        default : bkp_write_data(BKP_DATA_0, 0); goto CODE_BKP_INIT;
    }

    /* set RTC prescaler: set RTC period to 1s */
    rtc_prescaler_set(uiPrescaler);
    /* wait until last write operation on RTC registers has finished */
    rtc_lwoff_wait();

    /* wait for RTC registers synchronization */
    rtc_register_sync_wait();
    /* wait until last write operation on RTC registers has finished */
    rtc_lwoff_wait();

//    /* enable the RTC second interrupt*/
//    rtc_interrupt_enable(RTC_INT_SECOND);
//    /* wait until last write operation on RTC registers has finished */
//    rtc_lwoff_wait();

//    rtc_flag_clear(RTC_FLAG_ALARM);
//    rtc_interrupt_enable(RTC_INT_ALARM);
//    /* wait until last write operation on RTC registers has finished */
//    rtc_lwoff_wait();

//    nvic_irq_enable(RTC_IRQn, 1, 0);
//    nvic_irq_enable(RTC_Alarm_IRQn, 1, 0);

//    /* EXTI configuration */
//    exti_deinit();
//    exti_init(EXTI_17, EXTI_INTERRUPT, EXTI_TRIG_RISING);
//    exti_interrupt_flag_clear(EXTI_17);
//    exti_interrupt_enable(EXTI_17);

//    /* 设置闹钟时刻 */
//    vRtcAlarmSet(5);
}

/* 设置RTC时间 */
void vRtcTimestampSet(uint32_t uiTimestamp)
{
    /* change the current time */
    rtc_counter_set(uiTimestamp);
    /* wait until last write operation on RTC registers has finished */
    rtc_lwoff_wait();
}

/* 获取RTC时间 */
uint32_t uiRtcTimestampGet(void)
{
    /* read the current time */
    return rtc_counter_get();
}

/* 设置闹钟时刻 */
void vRtcAlarmSet(uint32_t uiTimestamp)
{
    /* set RTC alarm value */
    rtc_alarm_config(uiTimestamp);
    /* wait until last write operation on RTC registers has finished */
    rtc_lwoff_wait();
}


static void cRtcBkpInit(void)
{
    /* reset backup domain */
    bkp_deinit();

    /* 备份寄存器的值，如果是正常的0xA5A5，则表示系统关机后，RTC一直运行正常 */
    bkp_write_data(BKP_DATA_0, 0xA5A5);

    /*时区默认为 东八区*/
    vRtcUTCSet(8);
}

/* 设置BKP区域的值 */
int8_t cRtcBkpDataWrite(int8_t cChannel, uint16_t usValue)
{
    uint16_t usCrcCheck = 0xFFFF;
    int8_t i = 0;

    if((cChannel < 1) || (cChannel > 42))
        return 1;

    bkp_write_data((bkp_data_register_enum)cChannel, usValue);

    for(i = 1; i < 42; ++i)
    {
        usValue = bkp_read_data((bkp_data_register_enum)i);
        usCrcCheck = usCRC16_MODBUS(&usCrcCheck, (uint8_t *)&usValue, 2);
    }

    /* 最后一个数据区域保存CRC校验码 */
    bkp_write_data((bkp_data_register_enum)42, usCrcCheck);

    return 0;
}

/* 获取BKP区域的值 */
uint16_t usRtcBkpDataRead(int8_t cChannel)
{
    if((cChannel < 1) || (cChannel > 42))
        return 0;

    return bkp_read_data((bkp_data_register_enum)cChannel);
}

/* 设置RTC时区 */
void vRtcUTCSet(int8_t cUTC)
{
    cRtcBkpDataWrite(BKP_DATA_1, cUTC);
}

/* 获取RTC时区 */
int8_t cRtcUTCGet(void)
{
    /* 存储时区数据 */
    return bkp_read_data(BKP_DATA_1);
}
